﻿#ifdef _WIN32
#include "windows_defines.h"
#endif

#include "../../../../../../unittest/framework/unittest.hh"
#include "box/service_context.hh"
#include "box/service_box.hh"
#include "detail/lang_impl.hh"

#include "GuildServiceBasic/stub/guildservicebasic.service.GuildServiceBasic.stub.h"
#include "GuildServiceBasic/proxy/guildservicebasic.service.GuildServiceBasic.proxy.h"
#include "protobuf/guildservicebasic.service.pb.h"

#include "GuildServiceQuery/stub/guildservicequery.service.GuildServiceQuery.stub.h"
#include "GuildServiceQuery/proxy/guildservicequery.service.GuildServiceQuery.proxy.h"
#include "protobuf/guildservicequery.service.pb.h"


#include "../src/util/time_util.hh"


#include "GuildMember_struct.h"
#include "GuildModuleMembers_struct.h"
#include "AnnounceMsg_struct.h"
#include "AnnounceData_struct.h"
#include "GuildModuleBrief_struct.h"
#include "GuildApplicationInfo_struct.h"
#include "GuildModuleApplication_struct.h"

#include "CreateGuildArg_struct.h"
#include "CreateGuildRes_struct.h"
#include "ApplyJoinGuildArg_struct.h"
#include "ApplyJoinGuildRes_struct.h"
#include "KickOutGuildMemberArg_struct.h"
#include "KickOutGuildMemberRes_struct.h"
#include "QuitGuildArg_struct.h"
#include "QuitGuildRes_struct.h"
#include "SetAutoApprovalArg_struct.h"
#include "SetAutoApprovalRes_struct.h"
#include "ChangeGuildIconIdArg_struct.h"
#include "ChangeGuildIconIdRes_struct.h"
#include "ChangeGuildNameArg_struct.h"
#include "ChangeGuildNameRes_struct.h"
#include "ChangeGuildDeclarationArg_struct.h"
#include "ChangeGuildDeclarationRes_struct.h"
#include "ChangeGuildAnnounceArg_struct.h"
#include "ChangeGuildAnnounceRes_struct.h"

#include "GuildModuleApplication_struct.h"
#include "GetGuildBriefArg_struct.h"
#include "GetGuildBriefRes_struct.h"
#include "GetGuildMemberArg_struct.h"
#include "GetGuildMemberRes_struct.h"
#include "SearchGuildArg_struct.h"
#include "SearchGuildRes_struct.h"
#include "GetGuildBriefListArg_struct.h"
#include "GetGuildBriefListRes_struct.h"
#include "GetGuildApplicationArg_struct.h"
#include "GetGuildApplicationRes_struct.h"


#include <iostream>
#include <fstream>
#include <chrono>
#include <thread>

FIXTURE_BEGIN(test_service_box)

SETUP([]() {
    {
        std::ofstream ofs;
        ofs.open("config_service_box.cfg", std::ios::trunc | std::ios::out);
        ofs << "listener = {\r"
            "   host = (\"127.0.0.1:10001\")\r"
            "}\r"

            "box_channel_recv_buffer_len = 1024\r"
            "box_name = \"test_guild\"\r"

            "service = {\r"
            "   service_dir = "
            "\"../../../../tmp\"\r"
            "   preload_service = <3070737292341354930:\"libGuildServiceQuery.so\",7392537697003571364:\"libGuildServiceBasic.so\">\r"
            "}\r"

            "debugger = {\r"
            "   enable = \"true\"\r"
            "   listen = \"0.0.0.0:10888\"\r"
            "}\r"

            "service_finder = {\r"
            "   type = \"zookeeper\"\r"
            "   hosts = \"127.0.0.1:2181\"\r"
            "}\r"

            "statistics = {\r"
            "   is_open_rpc_stat = \"true\"\r"
            "}";
        ofs.close();
    }

    {
        std::ofstream ofs;
        ofs.open("config_service_box2.cfg", std::ios::trunc | std::ios::out);
        ofs << "listener = {\r"
            "   host = (\"127.0.0.1:10002\")\r"
            "}\r"
            "box_channel_recv_buffer_len = 1024\r"
            "box_name = \"test_dynamic2\""
            "service = {\r"
            "   service_dir = "
            "\"../../../../tmp\"\r"
            "}\r"
            "debugger = {\r"
            "   enable = \"true\"\r"
            "   listen = \"0.0.0.0:10888\"\r"
            "}\r"
            "service_finder = {\r"
            "   type = \"zookeeper\"\r"
            "   hosts = \"127.0.0.1:2181\"\r"
            "}\r"

            "statistics = {\r"
            "   is_open_rpc_stat = \"true\"\r"
            "}";
 
        ofs.close();
 
    }
})

CASE(TestServiceBox1) {
    std::cout << "Hello world" << std::endl;
}

CASE(TestServiceBox2) {

    kratos::service::ServiceBox service;
    const char *argv_service[] = {"test_service",
                                  "--config=config_service_box.cfg",
                                  "--proxy-host=127.0.0.1:10002"};

    ASSERT_TRUE(service.start(3, argv_service));

    service.register_service("guild_service_query");
    service.register_service("guild_service_basic");

    kratos::service::ServiceBox caller;
    const char *argv_caller[] = {"test_caller",
                                 "--config=config_service_box2.cfg",
                                 "--proxy-host=127.0.0.1:10001"};
    ASSERT_TRUE(caller.start(3, argv_caller));

    std::thread thread_service = std::thread([this, &service]() {
        auto start = kratos::util::get_os_time_millionsecond();
        while (true)
        {
            service.update();

            auto now = kratos::util::get_os_time_millionsecond();
            if (now - start > 3000)
            {
                break;
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
        });


    std::thread thread_caller = std::thread([this, &caller]() {
        auto start = kratos::util::get_os_time_millionsecond();
        while (true)
        {
            caller.update();

            auto now = kratos::util::get_os_time_millionsecond();
            if (now - start > 3000)
            {
                break;
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
        });
 
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));

    auto trans_query = caller.try_get_transport("guild_service_query");
    auto prx_query = rpc::getService<GuildServiceQueryProxy>(trans_query, false, caller.get_rpc());
    ASSERT_TRUE(prx_query != nullptr);

    auto trans_basic = caller.try_get_transport("guild_service_basic");
    auto prx_basic = rpc::getService<GuildServiceBasicProxy>(trans_basic, false, caller.get_rpc());
    ASSERT_TRUE(prx_basic != nullptr);


    if (prx_basic && prx_basic)
    {
        uint64_t guild_id = 0;
        {// create
            if (0)
            {// 协程单例 单进程无法实现
                co(
                    try {
                        CreateGuildArg arg;
                        arg.role_uuid = 1000;
                        arg.name = "guild1";
                        auto res = prx_basic->CreateGuild(arg);
                        guild_id = res->id;
                        std::cout << "result=" << static_cast<int>(res->result) << std::endl;
                    }
                    catch (std::exception ex)
                    {
                        std::cerr << "exception=" << ex.what() << std::endl;
                    }
                )
            }
            else
            {
                CreateGuildArg arg;
                arg.role_uuid = 1000;
                arg.name = "guild1";
                prx_basic->CreateGuild(arg, [&guild_id](const CreateGuildRes& res, rpc::RpcError err) {
                    guild_id = res.id;
                    std::cout << "result=" << static_cast<int>(res.result) << std::endl;
                    });
            }
        }
        {// find
            GetGuildBriefArg arg;
            prx_query->GetGuildBrief(arg, [](const GetGuildBriefRes& res, rpc::RpcError err) {
                });
        }
    }


    if (thread_caller.joinable())
    {
        thread_caller.join();
    }

    if (thread_service.joinable())
    {
        thread_service.join();
    }

    service.unregister_service("guild_service_query");
    service.unregister_service("guild_service_basic");

    caller.stop();
    service.stop();

}

FIXTURE_END(test_service_box)